Skip to content

Add the Golang CLI (vip-next) alongside the Node CLI - #3013

Open
rinatkhaziev wants to merge 32 commits into
trunkfrom
feature/go-cli
Open

Add the Golang CLI (vip-next) alongside the Node CLI#3013
rinatkhaziev wants to merge 32 commits into
trunkfrom
feature/go-cli

Conversation

@rinatkhaziev

@rinatkhaziev rinatkhaziev commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

What this is

The Go rewrite of the VIP CLI (vip-next), ported from the internal
vip-cli-golang repo at 72ef2f89 (feature/go-rewrite).

This is additive. The Node CLI is untouched and still ships as vip. The
Go binary ships as vip-next. Cutover is a separate, later PR.

How to read it

The 7,107-commit rewrite history is deliberately not replayed. The 28 commits
here are hand-authored to be read in order, bottom-up — primitives, then
transport, then domain, then the command surface, then verification and
release:

Commits Contents
1–2 Go module scaffolding, Makefile, Windows build script
3–8 Primitives, GraphQL schema/codegen/client, auth, app context
9–12 Read-only APIs, SQL/media/import, backup, deploy, sync
13 wp-cli shell, SSH, stream transport
14–17 dev-env: containers, lifecycle/proxy/host ops, env model, import/sync
18–23 Command surface, by command group
24–28 Parity harness, fixtures, CI, Buildkite signing, docs

Only the PR head is green. Individual commits are a reading device, not
bisect points.

Reviewers can skip commit 5internal/gql/generated.go, 8,935 lines of
genqlient output. make verify-gql-stale fails CI if it drifts from its
inputs.

Verification

Run locally against the branch head:

  • make build — clean
  • make test — 50 packages, no failures
  • make test-parity-unit — passes
  • make test-parity-unit-hostile — passes (proves fixtures are ambient-independent)
  • make lint — clean
  • make verify-gql-stale — generated bindings up to date

The Windows build is unverified locally. make.ps1 needs a Windows host.
It must be confirmed in CI before merge.

The Run Windows Tests job is the pre-existing Node workflow and is flaky
independently of this PR — it fails with Failed to connect to Docker on the
Windows runner, has failed the same way on unrelated branches, and passed four
times on this branch. This PR changes no Node or Windows-workflow files.

Parity

ci-go.yml builds the Node CLI (npm ci) and diffs vip-next against it, so
changes under src/ retrigger the workflow. 16 scenarios carry an accepted,
documented Node-vs-Go divergence recorded as expected_drift with a
normalized-output signature.

Fixtures under testdata/parity/ were scrubbed before this PR: the app-list
recordings carried real app IDs and a real repo name from a live capture, now
synthetic (42/43, wpcomvip/example-multisite). Two expected_drift
signatures were recomputed as a direct consequence; the drift reasons
(parity register 1.2 and 1.3, KEEP) are unchanged. SQL, archive and image
fixtures were inspected individually and were already synthetic.

ci-go had never actually run before this PR

Every ci-go run in vip-cli-golang is a startup_failure at 0s. This PR is
the first time the workflow has ever executed, which means the parity harness
had only ever been exercised locally on macOS. Three Linux-only defects fell
out, all fixed here, all in the harness rather than in product code:

  1. The keychain fallback notice. On a host with no D-Bus secret service,
    vip-next stores credentials in a 0600 file and says so once on stderr;
    the Node CLI has no equivalent concept and says nothing. That one line
    failed 32 of the differential scenarios. It is now normalized away globally
    (ambientStderrRules), and announced as a real user-visible difference in
    docs/CUTOVER-BREAKING-CHANGES.md section 4d. The warning itself stays —
    storing a credential in plaintext is worth saying out loud.

  2. The enquirer prompt scenarios. Three non-TTY prompt scenarios compared
    Node's raw prompt byte-for-byte, so their drift signatures were
    macOS-specific and could never have passed on Linux. Two things differ:
    the ANSI colour/cursor sequences, and — the one that actually broke them —
    enquirer's pointer glyph, U+203A on macOS and U+2023 on Linux. Both are
    normalized; signatures recomputed and now identical on both platforms.

  3. Diagnostics. A drift-signature mismatch used to report two hashes and
    nothing else, which says a blessed drift moved but not how. It now prints
    the normalized output the signature was taken over.

In every case the scenario's actual subject — the Node-vs-Go behavioural
divergence — is still compared in full. A test asserts the ambient rule stays
narrow enough that a real stderr message still diverges.

Notes for reviewers

  • go.mod/go.sum are intentionally not go mod tidy-clean. genqlient is
    run as a tool (go run github.com/Khan/genqlient) with no tools.go and no
    tool directive, so tidy cannot see its imports and strips 18 go.sum
    entries — which makes make verify-gql-stale fail. Please don't tidy.
  • ci-go.yml's three npm-shrinkwrap.json references were corrected to
    package-lock.json
    during the port. Neither repo has an
    npm-shrinkwrap.json; as written the npm cache missed and the workflow did
    not retrigger on lockfile changes.
  • devenv-e2e.yml and windows-tests.yml are deliberately not included.
    They already exist on trunk as Node workflows, and trunk's copies are newer
    than the rewrite branch's (checkout@v7/setup-node@v7 vs v6). Porting
    them would have silently reverted trunk's Node CI.
  • The Buildkite pipeline coexists with the existing sea-build-sign.yml, which
    signs the Node SEA build. Worth confirming they don't contend for the same
    Apple credentials, notarization profile, or agent queue.

Adds the Go module rooted at github.com/Automattic/vip, and the .gitignore
entries for Go build artifacts and the vendored go-search-replace binaries.
The schema.gql negation is required: the blanket schema.gql rule would
otherwise exclude internal/gql/schema.gql, which is checked in.

go.mod and go.sum are intentionally not `go mod tidy`-clean: tidy strips the
go.sum entries for genqlient's own dependencies, which breaks
`make verify-gql-stale`.

Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
third_party/go-search-replace/MANIFEST pins the go-search-replace release;
the per-platform binaries are fetched and checksum-verified by
`make vendor-search-replace` and stay out of git.

Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
The schema and the 19 .graphql operation documents are the codegen inputs;
the generated bindings land in the next commit so they can be reviewed
separately, or skipped.

Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Generated by genqlient from the schema and operations in the previous commit.
Regenerate with `make tidy-gql`; `make verify-gql-stale` fails CI if this
file drifts from its inputs. Reviewers can skip this file.

Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
The hand-written half of internal/gql: request execution, HTTP transport,
retry and backoff, error shaping, and the rechallenge hook that drives
step-up auth when the API demands it.

Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
searchreplace and sqlreport live here rather than with the root command:
both exist to serve `vip import sql`.

Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
All 36 files sit behind `//go:build parity` so they do not affect a normal
build. The harness diffs vip-next against the Node CLI built from src/;
`make test-parity-unit` runs it.

Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Recordings are scrubbed: app and environment IDs, hostnames, emails and
tokens are synthetic and internally consistent across sequenced fixtures.

Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
The Node CLI is a build input: the job runs `npm ci` and diffs vip-next
against it, so changes under src/ retrigger this workflow.

devenv-e2e.yml and windows-tests.yml are deliberately not touched — they are
existing Node workflows and trunk's copies are newer than the rewrite
branch's.

Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Builds, signs and notarizes vip-next for macOS, Linux and Windows, and
produces a universal stapled .pkg. Coexists with the existing
sea-build-sign.yml, which signs the Node SEA build.

Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
@github-actions

Copy link
Copy Markdown
Contributor

Dependency Review

The following issues were found:
  • ✅ 0 vulnerable package(s)
  • ✅ 0 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ⚠️ 6 package(s) with unknown licenses.
  • ⚠️ 2 packages with OpenSSF Scorecard issues.
See the Details below.

License Issues

.github/workflows/ci-go.yml

PackageVersionLicenseIssue Type
actions/checkout4.*.*NullUnknown License
actions/setup-go5.*.*NullUnknown License
actions/setup-node6.*.*NullUnknown License

Gemfile

PackageVersionLicenseIssue Type
fastlane~> 2.237NullUnknown License
fastlane-plugin-wpmreleasetoolkit~> 14.10NullUnknown License
openssl~> 4.0NullUnknown License

OpenSSF Scorecard

Scorecard details
PackageVersionScoreDetails
actions/actions/checkout 4.*.* 🟢 7
Details
CheckScoreReason
Maintained🟢 1024 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Code-Review🟢 10all changesets reviewed
Binary-Artifacts🟢 10no binaries found in the repo
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Fuzzing⚠️ 0project is not fuzzed
Packaging⚠️ -1packaging workflow not detected
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Pinned-Dependencies🟢 3dependency not pinned by hash detected -- score normalized to 3
Security-Policy🟢 9security policy file detected
SAST🟢 10SAST tool is run on all commits
Branch-Protection🟢 6branch protection is not maximal on development and all release branches
actions/actions/setup-go 5.*.* 🟢 6.1
Details
CheckScoreReason
Binary-Artifacts🟢 10no binaries found in the repo
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Packaging⚠️ -1packaging workflow not detected
Code-Review🟢 10all changesets reviewed
Maintained🟢 56 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 5
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies🟢 7dependency not pinned by hash detected -- score normalized to 7
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST🟢 10SAST tool is run on all commits
actions/actions/setup-node 6.*.* 🟢 6.4
Details
CheckScoreReason
Code-Review🟢 10all changesets reviewed
Maintained🟢 1021 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 9binaries present in source code
Packaging⚠️ -1packaging workflow not detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies🟢 5dependency not pinned by hash detected -- score normalized to 5
License🟢 10license file detected
Fuzzing⚠️ 0project is not fuzzed
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST🟢 10SAST tool is run on all commits
rubygems/fastlane ~> 2.237 UnknownUnknown
rubygems/fastlane-plugin-wpmreleasetoolkit ~> 14.10 UnknownUnknown
rubygems/openssl ~> 4.0 UnknownUnknown
gomod/github.com/AlecAivazis/survey/v2 2.3.7 🟢 3.9
Details
CheckScoreReason
Packaging⚠️ -1packaging workflow not detected
Code-Review🟢 7Found 23/30 approved changesets -- score normalized to 7
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Maintained⚠️ 0project is archived
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Binary-Artifacts🟢 10no binaries found in the repo
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/Khan/genqlient 0.8.1 UnknownUnknown
gomod/github.com/coder/websocket 1.8.15 UnknownUnknown
gomod/github.com/creack/pty 1.1.17 🟢 3.4
Details
CheckScoreReason
Maintained⚠️ 01 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Packaging⚠️ -1packaging workflow not detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Code-Review🟢 6Found 9/15 approved changesets -- score normalized to 6
Binary-Artifacts🟢 10no binaries found in the repo
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
Security-Policy⚠️ 0security policy file not detected
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/danieljoos/wincred 1.2.3 🟢 3.4
Details
CheckScoreReason
Code-Review🟢 3Found 3/10 approved changesets -- score normalized to 3
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Packaging⚠️ -1packaging workflow not detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/fatih/color 1.19.0 🟢 5.4
Details
CheckScoreReason
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
Code-Review🟢 10all changesets reviewed
Maintained🟢 1017 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Packaging⚠️ -1packaging workflow not detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Security-Policy⚠️ 0security policy file not detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/godbus/dbus/v5 5.2.2 🟢 6.6
Details
CheckScoreReason
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Token-Permissions🟢 10GitHub workflow tokens follow principle of least privilege
Code-Review🟢 7Found 7/10 approved changesets -- score normalized to 7
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Packaging⚠️ -1packaging workflow not detected
Security-Policy🟢 10security policy file detected
Binary-Artifacts🟢 10no binaries found in the repo
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Fuzzing🟢 10project is fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/golang-jwt/jwt/v5 5.3.1 🟢 7.8
Details
CheckScoreReason
Maintained🟢 55 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 5
Packaging⚠️ -1packaging workflow not detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Security-Policy🟢 10security policy file detected
Code-Review🟢 8Found 16/18 approved changesets -- score normalized to 8
Binary-Artifacts🟢 10no binaries found in the repo
Token-Permissions🟢 9detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies🟢 10all dependencies are pinned
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
SAST🟢 9SAST tool detected but not run on all commits
gomod/github.com/google/uuid 1.6.0 🟢 6.9
Details
CheckScoreReason
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Code-Review🟢 10all changesets reviewed
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Binary-Artifacts🟢 10no binaries found in the repo
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Packaging⚠️ -1packaging workflow not detected
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Fuzzing🟢 10project is fuzzed
License🟢 10license file detected
Token-Permissions🟢 10GitHub workflow tokens follow principle of least privilege
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
Security-Policy🟢 10security policy file detected
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/inconshreveable/mousetrap 1.1.0 ⚠️ 2.1
Details
CheckScoreReason
Dangerous-Workflow⚠️ -1no workflows found
Pinned-Dependencies⚠️ -1no dependencies found
Packaging⚠️ -1packaging workflow not detected
Binary-Artifacts🟢 10no binaries found in the repo
Code-Review⚠️ 1Found 2/16 approved changesets -- score normalized to 1
Token-Permissions⚠️ -1No tokens found
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/kballard/go-shellquote 0.0.0-20180428030007-95032a82bc51 ⚠️ 2.3
Details
CheckScoreReason
Dangerous-Workflow⚠️ -1no workflows found
Binary-Artifacts🟢 10no binaries found in the repo
Code-Review⚠️ 2Found 3/14 approved changesets -- score normalized to 2
Packaging⚠️ -1packaging workflow not detected
Pinned-Dependencies⚠️ -1no dependencies found
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Token-Permissions⚠️ -1No tokens found
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Fuzzing⚠️ 0project is not fuzzed
Security-Policy⚠️ 0security policy file not detected
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/mattn/go-colorable 0.1.14 🟢 3.9
Details
CheckScoreReason
Maintained🟢 45 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 4
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Code-Review🟢 7Found 11/15 approved changesets -- score normalized to 7
Binary-Artifacts🟢 10no binaries found in the repo
Packaging⚠️ -1packaging workflow not detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
Security-Policy⚠️ 0security policy file not detected
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/mattn/go-isatty 0.0.20 🟢 4.2
Details
CheckScoreReason
Binary-Artifacts🟢 10no binaries found in the repo
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Packaging⚠️ -1packaging workflow not detected
Maintained🟢 103 commit(s) and 9 issue activity found in the last 90 days -- score normalized to 10
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Code-Review🟢 4Found 9/21 approved changesets -- score normalized to 4
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Security-Policy⚠️ 0security policy file not detected
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/mattn/go-runewidth 0.0.16 🟢 4.7
Details
CheckScoreReason
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
Security-Policy🟢 10security policy file detected
Code-Review⚠️ 2Found 4/15 approved changesets -- score normalized to 2
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Packaging⚠️ -1packaging workflow not detected
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Maintained🟢 1017 commit(s) and 9 issue activity found in the last 90 days -- score normalized to 10
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/mgutz/ansi 0.0.0-20170206155736-9520e82c474b UnknownUnknown
gomod/github.com/pkg/browser 0.0.0-20240102092130-5ac0b6a4141c 🟢 3.3
Details
CheckScoreReason
Code-Review🟢 5Found 11/19 approved changesets -- score normalized to 5
Packaging⚠️ -1packaging workflow not detected
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Binary-Artifacts🟢 10no binaries found in the repo
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
Signed-Releases⚠️ -1no releases found
License🟢 10license file detected
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/rivo/uniseg 0.4.7 🟢 3.8
Details
CheckScoreReason
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Token-Permissions⚠️ -1No tokens found
Dangerous-Workflow⚠️ -1no workflows found
Code-Review🟢 5Found 8/15 approved changesets -- score normalized to 5
Packaging⚠️ -1packaging workflow not detected
Binary-Artifacts🟢 10no binaries found in the repo
Pinned-Dependencies⚠️ -1no dependencies found
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
License🟢 10license file detected
Fuzzing🟢 10project is fuzzed
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/spf13/cobra 1.10.2 🟢 6.2
Details
CheckScoreReason
Binary-Artifacts🟢 10no binaries found in the repo
Maintained⚠️ 21 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 2
Security-Policy🟢 10security policy file detected
Code-Review🟢 8Found 22/25 approved changesets -- score normalized to 8
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Packaging⚠️ -1packaging workflow not detected
Token-Permissions🟢 10GitHub workflow tokens follow principle of least privilege
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/spf13/pflag 1.0.9 🟢 6.3
Details
CheckScoreReason
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Maintained🟢 1016 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 10
Packaging⚠️ -1packaging workflow not detected
Token-Permissions🟢 10GitHub workflow tokens follow principle of least privilege
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Code-Review🟢 8Found 12/15 approved changesets -- score normalized to 8
Binary-Artifacts🟢 10no binaries found in the repo
Pinned-Dependencies🟢 10all dependencies are pinned
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/vektah/gqlparser/v2 2.5.19 🟢 4.9
Details
CheckScoreReason
Maintained🟢 1022 commit(s) and 3 issue activity found in the last 90 days -- score normalized to 10
Packaging⚠️ -1packaging workflow not detected
Code-Review🟢 8Found 10/12 approved changesets -- score normalized to 8
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Binary-Artifacts🟢 10no binaries found in the repo
Pinned-Dependencies🟢 4dependency not pinned by hash detected -- score normalized to 4
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/zalando/go-keyring 0.2.8 🟢 8.3
Details
CheckScoreReason
Maintained🟢 1012 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Binary-Artifacts🟢 10no binaries found in the repo
Security-Policy🟢 10security policy file detected
Packaging⚠️ -1packaging workflow not detected
Code-Review🟢 10all changesets reviewed
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Pinned-Dependencies🟢 7dependency not pinned by hash detected -- score normalized to 7
Token-Permissions🟢 10GitHub workflow tokens follow principle of least privilege
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
License🟢 10license file detected
Fuzzing⚠️ 0project is not fuzzed
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
SAST🟢 6SAST tool is not run on all commits -- score normalized to 6
gomod/golang.org/x/crypto 0.53.0 UnknownUnknown
gomod/golang.org/x/net 0.55.0 UnknownUnknown
gomod/golang.org/x/sys 0.46.0 UnknownUnknown
gomod/golang.org/x/term 0.44.0 UnknownUnknown
gomod/golang.org/x/text 0.38.0 UnknownUnknown
gomod/gopkg.in/yaml.v3 3.0.1 UnknownUnknown

Scanned Files

  • .github/workflows/ci-go.yml
  • Gemfile
  • go.mod

Comment on lines +46 to +113
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.27'
check-latest: true
cache: true

# The Node CLI is the reference implementation the differential parity
# scenarios diff vip-next against. Without it, every Node-vs-Go scenario
# skips and this job goes green having compared nothing — which is
# exactly how ~90 parity divergences reached a review unnoticed.
#
# Version comes from .nvmrc (lts/*), the same source ci.yml pins by hand.
# It must satisfy package.json#engines (>=22.19.0 on trunk 4.1.0) or the
# `postinstall` guard (helpers/check-version.js) aborts the install with
# exit 1.
- name: Set up Node.js environment
uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
cache: npm
cache-dependency-path: package-lock.json

# `npm ci` runs the `prepare` lifecycle script (clean + babel build),
# which is what produces dist/bin/vip.js. No separate build step needed.
- name: Install Node dependencies and build the Node CLI
run: npm ci

# Fail loudly if the above did not actually yield a runnable Node CLI.
# `make test-parity-unit` only WARNS in that case, on purpose, so that a
# contributor without node_modules is not hard-failed. CI has no such
# excuse: here a skipped differential is a broken build.
- name: Assert the Node-vs-Go differential can actually run
run: make require-node-vip-bin

- name: go mod download
run: go mod download

- name: Verify generated GraphQL code is fresh
run: make verify-gql-stale

# Via make, not bare `go vet ./...` / `go test ./...`: now that `npm ci`
# has run, node_modules is inside the module and a bare `./...` would
# compile and vet an npm dependency's vendored Go package
# (node_modules/flatted/golang/pkg/flatted). The make targets discover
# the package list and drop node_modules from it.
- name: go vet
run: make lint

- name: go test
run: make test

# This is the step the Node CLI was installed for. On a Linux runner the
# credential the Node CLI reads comes from configstore rather than a
# system keyring (see internal/parity/keychain.go); the harness seeds
# through Node's own getKeychain(), so it lands in whichever store Node
# itself would read, and a store that cannot be driven at all produces a
# loud skip rather than a hang or a false pass.
- name: Offline compatibility and parity-harness tests
run: make test-parity-unit

- name: make build
run: make build

- name: smoke
run: ./bin/vip-next --version
@rinatkhaziev rinatkhaziev changed the title Add the Go CLI (vip-next) alongside the Node CLI Add the Golang CLI (vip-next) alongside the Node CLI Aug 20, 2026
The Node repo runs prettier and eslint over the whole checkout, so landing the
Go tree made both fail: prettier flagged 214 files and eslint flagged
internal/wpstream/testdata/fixture-server.js, a WebSocket server fixture for
Go tests.

The parity recordings under testdata/ must stay byte-exact. Reformatting them
would change the payloads the harness replays and invalidate the
expected_drift signatures, so they are ignored rather than reformatted.

The four new docs and .buildkite/pipeline.yml are prettier-formattable and are
simply formatted to the repo's style; pipeline.yml was re-validated as YAML
after formatting.

Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
ci-go had never actually executed before this PR — every run of it in
vip-cli-golang is a startup_failure at 0s — so the harness had only ever run
on macOS, where an OS keyring is always available.

On a headless Linux runner there is no D-Bus secret service, so vip-next falls
back to a 0600 credentials file and says so once on stderr. The Node CLI uses
configstore and has no equivalent concept, so it says nothing. That one line
failed 32 differential scenarios on Linux that all pass on macOS.

The divergence is real and user-visible, so the warning stays and is announced
in docs/CUTOVER-BREAKING-CHANGES.md (new section 4d). What changes is the
harness: ambientStderrRules strips environment-dependent noise before any
comparison, including before the expected_drift signature is computed, so an
accepted divergence fingerprints identically on both platforms.

Recorded once as an environment property rather than as 32 per-scenario
expected_drift entries, because it appears in every scenario on one platform
and none on the other.

The rule is deliberately one anchored whole-line pattern; a test asserts that a
real stderr message still diverges, since a pattern one character too broad
would blind the harness to what it exists to catch.

Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
Three things, all aimed at the four scenarios still failing on Linux:

A signature mismatch previously reported two hashes and nothing else, which
says a blessed drift moved but not how, and turns every mismatch into a
bisect. It now prints the normalized output the signature was taken over.

TestPhpmyadminSilentParity asserts on stderr directly rather than through
Diff, so the ambient keychain notice reached it untouched. It now strips the
same ambient rules, testing the flag rather than the runner. Whether --silent
ought to suppress that notice too is a real question about the flag's
contract, and a separate one.

The three envvar prompt scenarios gained an ANSI strip on stderr, since Node
renders those prompts through enquirer. That strip is a no-op on macOS, so it
is not yet confirmed to be what differs on Linux — the improved diagnostics
above are there to find out.

Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
The three non-TTY prompt scenarios compared Node's raw enquirer output
byte-for-byte, which made their drift signatures macOS-specific. They could
never have passed on Linux, which went unnoticed because ci-go had never
actually run.

Two platform-dependent things, both on stdout rather than stderr:

  - colour and cursor-control sequences around the prompt
  - the pointer glyph, U+203A on macOS and U+2023 on Linux

The second is what actually broke these in CI; the ANSI rule alone was not
enough. Both are now normalized, the glyph to a literal <POINTER> so the
substitution is visible in any future diff rather than silently erased.

Signatures are recomputed over the normalized text and are now identical on
both platforms. The prompt's wording survives normalization, so the drift
these scenarios exist to record - Node prompting where vip-next refuses to in
a non-interactive shell - is still compared in full.

Ported from vip-cli-golang@72ef2f89 (feature/go-rewrite).
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants